package cn.getech.data.development.controller;

import cn.getech.data.development.constant.ConnectTypeEnum;
import cn.getech.data.development.constant.DBTypeEnum;
import cn.getech.data.development.constant.DataDevelopmentBizExceptionEnum;
import cn.getech.data.development.constant.LastRunState;
import cn.getech.data.development.entity.JobInfo;
import cn.getech.data.development.entity.JobRunHistory;
import cn.getech.data.development.service.CountTableRowsNumService;
import cn.getech.data.development.service.JobInfoService;
import cn.getech.data.development.service.JobRunHistoryService;
import cn.getech.data.development.service.ProcInfoService;
import cn.getech.data.intelligence.common.exception.RRException;
import cn.getech.data.intelligence.common.utils.R;
import cn.getech.system.center.annotation.SysLog;
import cn.getech.system.center.constant.OperationModulesEnum;
import cn.getech.system.center.constant.OperationTypeEnum;
import cn.getech.system.center.constant.module.ModuleEnum;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目概览相关
 *
 * @author zenith
 * @Date 2018-08-23 18:36:33
 */
@Api(tags = "项目概览相关")
@RestController
@RequestMapping("/bdp/procDash")
public class ProcInfoDashController {


    @Autowired
    private ProcInfoService procInfoService;
    @Autowired
    private JobInfoService jobInfoService;
    @Autowired
    private JobRunHistoryService jobRunHistoryService;
    @Autowired
    private CountTableRowsNumService countTableRowsNumService;

    @ApiOperation("项目中的数据源类型分布")
    @GetMapping("/connectTypes/{id}")
    @SysLog(value="项目中的数据源类型分布",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R connectTypes(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Integer>> list = procInfoService.connectTypes(id);
            Map<String, Integer> data = new HashMap<>();

            //初始化
            for (ConnectTypeEnum connectTypeEnum : ConnectTypeEnum.values()
            ) {
                data.put(connectTypeEnum.getName(), 0);
            }
            for (Map<String, Integer> t : list
            ) {
                data.put(ConnectTypeEnum.ObjOf(t.get("type_id")).getName(), t.get("c"));
            }

            return R.okWithData(data);
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("项目中的数据表类型分布")
    @GetMapping("/tableTypes/{id}")
    @SysLog(value="项目中的数据表类型分布",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R tableTypes(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Object>> list = procInfoService.tableTypes(id);
            Map<String, Integer> data = new HashMap<>();
            //初始化
            for (DBTypeEnum dbTypeEnum : DBTypeEnum.values()
            ) {
                data.put(dbTypeEnum.getName(), 0);
            }
            for (Map<String, Object> t : list
            ) {
                data.put(t.get("db_name").toString(), Integer.parseInt(t.get("c").toString()));
            }
            return R.okWithData(data);
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("项目中的失败任务分布")
    @GetMapping("/jobAlerts/{id}")
    @SysLog(value="项目中的失败任务分布",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R jobAlerts(@PathVariable("id") Integer id) {
        try {
            List<JobInfo> jobs = jobInfoService.list(new QueryWrapper<JobInfo>().eq("proc_id", id));
            List<Integer> jobIds = new ArrayList<>();
            for (JobInfo jobInfo : jobs
            ) {
                jobIds.add(jobInfo.getId());
            }
            if (jobIds.size() == 0) {
                jobIds.add(-1);
            }
            List<JobRunHistory> jobRunHistorys = jobRunHistoryService.getInfoByJobId(jobIds);
            Set<Integer> jobid = new HashSet<>();
            for (JobRunHistory jobRunHistory : jobRunHistorys
            ) {
                jobid.add(jobRunHistory.getJobInfoId());
            }

            Map<String, Integer> data = new HashMap<>();
            Map<String, Integer> result = new LinkedHashMap<>();

            for (Integer i : jobid
            ) {
                String jobName = jobInfoService.getById(i).getName();
                data.put(jobName, jobRunHistorys.stream().filter(jobRunHistory -> ObjectUtil.equal(jobRunHistory.getJobInfoId(), i)).collect(Collectors.toList()).size());
            }
            List<Map.Entry<String, Integer>> lists = new ArrayList<Map.Entry<String, Integer>>(data.entrySet());
            Collections.sort(lists, new Comparator<Map.Entry<String, Integer>>() {
                public int compare(Map.Entry<String, Integer> map1, Map.Entry<String, Integer> map2) {
                    return (map2.getValue() - map1.getValue());
                }
            });

            if (lists.size() >= 10) {
                for (Map.Entry<String, Integer> set : lists.subList(0, 10)) {
                    result.put(set.getKey(), set.getValue());
                }
            } else {
                for (Map.Entry<String, Integer> set : lists) {
                    result.put(set.getKey(), set.getValue());
                }
            }
            return R.okWithData(result);
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }


    @ApiOperation("项目中的任务监控统计")
    @GetMapping("/jobMonitor/{id}")
    @SysLog(value="项目中的任务监控统计",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R jobMonitor(@PathVariable("id") Integer id) {
        try {
            Map<String, Map<String, Integer>> data = new HashMap<>();

            Map<String, Integer> last1HourRate = genRe(procInfoService.last1Hour(id));
            Map<String, Integer> last6HourRate = genRe(procInfoService.last6Hour(id));
            Map<String, Integer> last1DayRate = genRe(procInfoService.last1Day(id));
            Map<String, Integer> last1WeekRate = genRe(procInfoService.last1Week(id));
            Map<String, Integer> last1MonthRate = genRe(procInfoService.last1Month(id));

            data.put("last1HourRate", last1HourRate);
            data.put("last6HourRate", last6HourRate);
            data.put("last1DayRate", last1DayRate);
            data.put("last1WeekRate", last1WeekRate);
            data.put("last1MonthRate", last1MonthRate);
            return R.okWithData(data);
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    private Map<String, Integer> genRe(List<Map<String, Object>> list) {
        Map<String, Integer> re = new HashMap<>();
        Integer success = 0;
        Integer fail = 0;
        for (Map<String, Object> t : list
        ) {
            if ((Integer) t.get("last_run_state") == LastRunState.SUCCESS.getCode()) {
                success += Integer.parseInt(String.valueOf(t.get("c")));
            } else {
                fail += Integer.parseInt(String.valueOf(t.get("c")));
            }
        }
        re.put("success", success);
        re.put("fail", fail);
        if (success + fail == 0) {
            re.put("rate", 0);
        } else {
            re.put("rate", success * 100 / (success + fail));
        }

        return re;
    }

    @ApiOperation("项目中的最近任务详情")
    @GetMapping("/last1Hour/{id}")
    @SysLog(value="项目中的最近任务详情",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R last1Hour(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Object>> dataList = procInfoService.last1Hour(id);
            List<DateTime> runTimeList = DateUtil.rangeToList(DateUtil.offsetHour(DateUtil.date(), -1), DateUtil.date(), DateField.MINUTE);
            return R.okWithData(genMinuteList(runTimeList, dataList));
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("项目中的最近6小时任务统计")
    @GetMapping("/last6Hour/{id}")
    @SysLog(value="项目中的最近6小时任务统计",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R last6Hour(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Object>> dataList = procInfoService.last6Hour(id);
            List<DateTime> runTimeList = DateUtil.rangeToList(DateUtil.offsetHour(DateUtil.date(), -6), DateUtil.date(), DateField.MINUTE);
            return R.okWithData(genMinuteList(runTimeList, dataList));
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("项目中的最近1天任务统计")
    @GetMapping("/last1Day/{id}")
    @SysLog(value="项目中的最近1天任务统计",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R last1Day(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Object>> dataList = procInfoService.last1Day(id);
            List<DateTime> runTimeList = DateUtil.rangeToList(DateUtil.offsetDay(DateUtil.date(), -1), DateUtil.date(), DateField.HOUR);
            return R.okWithData(genHourList(runTimeList, dataList));
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("项目中的最近1周任务统计")
    @GetMapping("/last1Week/{id}")
    @SysLog(value="项目中的最近1周任务统计",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R last1Week(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Object>> dataList = procInfoService.last1Week(id);
            List<DateTime> runTimeList = DateUtil.rangeToList(DateUtil.offsetWeek(DateUtil.date(), -1), DateUtil.date(), DateField.DAY_OF_MONTH);
            return R.okWithData(genDayList(runTimeList, dataList));
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("项目中的最近1小时任务统计")
    @GetMapping("/last1Month/{id}")
    @SysLog(value="项目中的最近1小时任务统计",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R last1Month(@PathVariable("id") Integer id) {
        try {
            List<Map<String, Object>> dataList = procInfoService.last1Month(id);
            List<DateTime> runTimeList = DateUtil.rangeToList(DateUtil.offsetMonth(DateUtil.date(), -1), DateUtil.date(), DateField.DAY_OF_MONTH);
            return R.okWithData(genDayList(runTimeList, dataList));
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    private Map<String, Object> genMinuteList(List<DateTime> runTimeList, List<Map<String, Object>> dataList) {
        Map<String, Object> re = new HashMap<>();
        List<String> time = new ArrayList<>();
        List<Integer> success = new ArrayList<>();
        List<Integer> fail = new ArrayList<>();
        for (DateTime runTime : runTimeList
        ) {
            String rt = runTime.toString(new SimpleDateFormat("HH-mm"));
            time.add(String.format("%s时%s分", rt.split("-")[0], rt.split("-")[1]));
            dealData(dataList, success, fail, rt);
        }
        re.put("runTime", time);
        re.put("success", success);
        re.put("fail", fail);
        return re;
    }

    private Map<String, Object> genHourList(List<DateTime> runTimeList, List<Map<String, Object>> dataList) {
        HashMap<String, Object> re = new HashMap<>();
        List<String> time = new ArrayList<>();
        List<Integer> success = new ArrayList<>();
        List<Integer> fail = new ArrayList<>();
        for (DateTime runTime : runTimeList
        ) {
            String rt = runTime.toString(new SimpleDateFormat("dd-HH"));
            time.add(String.format("%s日%s时", rt.split("-")[0], rt.split("-")[1]));
            dealData(dataList, success, fail, rt);
        }
        re.put("runTime", time);
        re.put("success", success);
        re.put("fail", fail);
        return re;
    }

    private Map<String, Object> genDayList(List<DateTime> runTimeList, List<Map<String, Object>> dataList) {
        Map<String, Object> re;
        re = new HashMap<>();
        List<String> time = new ArrayList<>();
        List<Integer> success = new ArrayList<>();
        List<Integer> fail = new ArrayList<>();
        for (DateTime runTime : runTimeList
        ) {
            String rt = runTime.toString(new SimpleDateFormat("MM-dd"));
            time.add(String.format("%s月%s日", rt.split("-")[0], rt.split("-")[1]));
            dealData(dataList, success, fail, rt);
        }
        re.put("runTime", time);
        re.put("success", success);
        re.put("fail", fail);
        return re;
    }

    private void dealData(List<Map<String, Object>> dataList, List<Integer> success, List<Integer> fail, String rt) {
        Integer successCount = 0;
        Integer failCount = 0;
        for (Map<String, Object> info : dataList
        ) {
            //匹配
            Boolean isMatch;
            if (rt.contains("-")) {
                String[] run_times = info.get("run_time").toString().split("-");
                String[] rts = rt.split("-");
                isMatch = Integer.parseInt(run_times[0]) == Integer.parseInt(rts[0]) && Integer.parseInt(run_times[1]) == Integer.parseInt(rts[1]);
            } else {
                isMatch = Integer.parseInt(info.get("run_time").toString()) == Integer.parseInt(rt);
            }
            if (isMatch) {
                if ((Integer) info.get("last_run_state") == LastRunState.SUCCESS.getCode()) {
                    success.add(Integer.parseInt(info.get("c").toString()));
                    successCount++;
                }
                if ((Integer) info.get("last_run_state") == LastRunState.FAIL.getCode()) {
                    fail.add(Integer.parseInt(info.get("c").toString()));
                    failCount++;
                }
            }
        }
        if (successCount == 0) {
            success.add(0);
        }
        if (failCount == 0) {
            fail.add(0);
        }
    }


    @ApiOperation("统计数据库行数大小以及大表信息")
    @GetMapping("/countDbRowsAndSize/{proc_id}")
    @SysLog(value="统计数据库行数大小以及大表信息",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R countDbRowsAndSize(@PathVariable("proc_id") Integer proc_id) {
        try {
            Map<String,Object> countResult= countTableRowsNumService.countTableRowsNumsAndSize(proc_id);
            return R.okWithData(countResult);
        } catch (Exception e) {
            throw new RRException(DataDevelopmentBizExceptionEnum.SERVER_ERROR.getMessage());
        }
    }

    @ApiOperation("统计数据库行数大小以及大表信息")
    @GetMapping("/postCountTableRowsNum")
    @SysLog(value="统计数据库行数大小以及大表信息",type= OperationTypeEnum.SELECTCODE, modulesType = OperationModulesEnum.BDPMODELCODE,platformModuleType = ModuleEnum.DATA_VIEW_MODULE_CODE)
    public R postCountTableRowsNum() {
        countTableRowsNumService.postCountTableRowsNum();
        return R.ok();
    }

}
